package p.ithorns.sample.minio.utils;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * StringUtil
 * <p>
 * 字符串工具类
 *
 * @author ithorns
 * @version 1.0
 * @date 2020/4/22 9:32
 */
public class StringUtil {

    /**
     * 空字符
     */
    public static final String EMPTY = "";

    /**
     * 字符串 is
     */
    public static final String IS = "is";

    /**
     * 下划线字符
     */
    public static final char UNDERLINE = '_';

    /**
     * 逗号分隔符
     */
    public static final String COMMA = ",";

    private final static Pattern PT_CAPITAL = Pattern.compile("[A-Z]");

    private final static Pattern PT_WORD = Pattern.compile("_(\\w)");

    /**
     * 左补白
     * 右补齐
     *
     * @param src -源字符串
     * @param len -补齐长度
     * @param ch  -补齐字符
     * @return String
     */
    public static String padLeft(String src, int len, char ch) {
        int srcLen = src.length();
        int diff = len - srcLen;
        if (diff <= 0) {
            return src;
        }

        char[] charr = new char[len];
        System.arraycopy(src.toCharArray(), 0, charr, 0, src.length());
        for (int i = src.length(); i < len; i++) {
            charr[i] = ch;
        }
        return new String(charr);
    }

    /**
     * 右补齐
     *
     * @param src -源字符串
     * @param len -补齐长度
     * @param ch  -补齐字符
     * @return String
     */
    public static String padRight(String src, int len, char ch) {
        int diff = len - src.length();
        if (diff <= 0) {
            return src;
        }

        char[] charr = new char[len];
        System.arraycopy(src.toCharArray(), 0, charr, diff, src.length());
        for (int i = 0; i < diff; i++) {
            charr[i] = ch;
        }
        return new String(charr);
    }

    /**
     * 判空
     *
     * @param cs
     * @return
     */
    public static boolean isEmpty(CharSequence cs) {
        return cs == null || cs.length() == 0;
    }

    /**
     * 判断非空
     *
     * @param cs
     * @return
     */
    public static boolean isNotEmpty(CharSequence cs) {
        return !isEmpty(cs);
    }

    /**
     * 判空(包括空白字符串)
     *
     * @param cs -源
     * @return String
     */
    public static boolean isBlank(CharSequence cs) {
        int strLen;
        if (cs != null && (strLen = cs.length()) != 0) {
            for (int i = 0; i < strLen; ++i) {
                if (!Character.isWhitespace(cs.charAt(i))) {
                    return false;
                }
            }

            return true;
        } else {
            return true;
        }
    }

    /**
     * 判断非空(包括空白字符串)
     *
     * @param cs -源
     * @return String
     */
    public static boolean isNotBlank(CharSequence cs) {
        return !isBlank(cs);
    }

    private static final String HEX_CHAR = "0123456789ABCDEF";

    /**
     * 转二进制字符串
     *
     * @param src -源
     * @return String
     */
    public static String toBinaryStr(String src) {
        StringBuilder sbuf = new StringBuilder();
        for (char c : src.toCharArray()) {
            int i = HEX_CHAR.indexOf(c);
            String s = Integer.toBinaryString(i);
            if (s.length() > 4) {
                s = s.substring(0, 4);
            }
            sbuf.append(String.format("%04d", Short.valueOf(s)));
        }

        return sbuf.toString();
    }

    /**
     * 去除所有空白字符
     *
     * @param src -源
     * @return String
     */
    public static String trimAllWhitespace(String src) {
        if (!hasLength(src)) {
            return EMPTY;
        } else {
            int len = src.length();
            StringBuilder sb = new StringBuilder(src.length());

            for (int i = 0; i < len; ++i) {
                char c = src.charAt(i);
                if (!Character.isWhitespace(c)) {
                    sb.append(c);
                }
            }

            return sb.toString();
        }
    }

    /**
     * 去除首尾空格(中文/全角)
     */
    public static String trimLeadTailWhitespace(String str) {
        if (!hasLength(str)) {
            return str;
        }

        int beginIdx = 0;
        while (beginIdx < str.length() && Character.isWhitespace(str.charAt(beginIdx))) {
            beginIdx++;
        }
        str = str.substring(beginIdx);

        int endIdx = str.length() - 1;
        while (endIdx >= 0 && Character.isWhitespace(str.charAt(endIdx))) {
            endIdx--;
        }
        return str.substring(0, endIdx + 1);
    }


    /**
     * 判断是否有长度
     *
     * @param src
     * @return boolean
     */
    public static boolean hasLength(String src) {
        return src != null && !src.isEmpty();
    }

    /**
     * 全部替换
     *
     * @param src         -源
     * @param regex       -正则
     * @param replacement -替换
     * @return String
     */
    public static String replaceAll(String src, String regex, String replacement) {
        return src != null && regex != null && replacement != null ? src.replaceAll(regex, replacement) : src;
    }

    /**
     * 分隔字符串数组
     * (逗号分隔符)
     *
     * @param toSplit -待分隔字符串
     * @return String[]
     */
    public static String[] split(@Nonnull String toSplit) {
        final String s = trimAllWhitespace(toSplit);
        if (isBlank(s)) {
            return new String[0];
        }
        return s.split(COMMA);
    }

    /**
     * 指定分隔符分隔字符串数组
     *
     * @param toSplit   -待分隔字符串
     * @param delimiter -分隔符
     * @return String[]
     */
    public static String[] split(@Nonnull String toSplit, @Nonnull String delimiter) {
        final String s = trimAllWhitespace(toSplit);
        if (isBlank(s)) {
            return new String[0];
        }
        return s.split(delimiter);
    }

    public static boolean hasText(@Nullable String str) {
        return str != null && !str.isEmpty() && containsText(str);
    }

    private static boolean containsText(CharSequence str) {
        int strLen = str.length();

        for (int i = 0; i < strLen; ++i) {
            if (!Character.isWhitespace(str.charAt(i))) {
                return true;
            }
        }

        return false;
    }

    public static String bytesToHexStr(byte[] src) {
        return bytesToHexStr(src, "");
    }

    /**
     * Convert byte[] to hex
     * string.这里可以将byte转换成int，然后利用Integer.toHexString(int)来转换成16进制字符串。
     *
     * @param src byte[] img
     * @return hex string
     */

    public static String bytesToHexStr(byte[] src, String split) {
        StringBuilder buffer = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (byte b : src) {
            int v = b & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                buffer.append(0);
            }
            buffer.append(hv.toUpperCase());
            buffer.append(split);
        }
        if (split.length() > 0) {
            buffer.setLength(buffer.length() - split.length());
        }
        return buffer.toString();
    }


    /**
     * 字符串驼峰转下划线格式
     *
     * @param param 需要转换的字符串
     * @return 转换好的字符串
     */
    public static String camelToUnderline(String param) {
        if (isBlank(param)) {
            return EMPTY;
        }
        int len = param.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = param.charAt(i);
            if (Character.isUpperCase(c) && i > 0) {
                sb.append(UNDERLINE);
            }
            sb.append(Character.toLowerCase(c));
        }
        return sb.toString();
    }

    public static String getFileSuffix(String fileName) {
        //获取最后一个.的位置
        int lastIndexOf = fileName.lastIndexOf(".");
        //获取文件的后缀名 .jpg
        return fileName.substring(lastIndexOf);
    }


    /**
     * 字符串转List
     *
     * @param str -待处理字符串
     * @return List
     */
    public static List<String> split2List(String str) {
        return new LinkedList<>(Arrays.asList(split(str)));
    }

    /**
     * 字符串转Set
     *
     * @param str -待处理字符串
     * @return Set
     */
    public static Set<String> split2Set(String str) {
        return new LinkedHashSet<>(Arrays.asList(split(str)));
    }

    public static Set<String> split2Set(String str, String delimiter) {
        return new LinkedHashSet<>(Arrays.asList(split(str, delimiter)));
    }

    /**
     * 指定字符串计算8位uuid
     *
     * @param str - 源字符串
     * @return String
     */
    public static StringBuffer camel(StringBuffer str) {
        //利用正则删除下划线，把下划线后一位改成大写
        Matcher matcher = PT_WORD.matcher(str);
        StringBuffer sb = new StringBuffer(str);
        if (matcher.find()) {
            sb = new StringBuffer();
            //将当前匹配子串替换为指定字符串，并且将替换后的子串以及其之前到上次匹配子串之后的字符串段添加到一个StringBuffer对象里。
            //正则之前的字符和被替换的字符
            matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
            //把之后的也添加到StringBuffer对象里
            matcher.appendTail(sb);
        } else {
            return sb;
        }
        return camel(sb);
    }

    /**
     * 驼峰转下划线
     *
     * @param str
     * @return
     */
    public static StringBuffer underline(StringBuffer str) {
        Matcher matcher = PT_CAPITAL.matcher(str);
        StringBuffer sb = new StringBuffer(str);
        if (matcher.find()) {
            sb = new StringBuffer();
            //将当前匹配子串替换为指定字符串，并且将替换后的子串以及其之前到上次匹配子串之后的字符串段添加到一个StringBuffer对象里。
            //正则之前的字符和被替换的字符
            matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
            //把之后的也添加到StringBuffer对象里
            matcher.appendTail(sb);
        } else {
            return sb;
        }
        return underline(sb);
    }

    /**
     * 对字符串md5加密(小写+字母)
     *
     * @param str 传入要加密的字符串
     * @return MD5加密后的字符串
     */
    public static String md5(String str) {
        try {
            // 生成一个MD5加密计算摘要
            MessageDigest md = MessageDigest.getInstance("MD5");
            // 计算md5函数
            md.update(str.getBytes());
            // digest()最后确定返回md5 hash值，返回值为8为字符串。因为md5 hash值是16位的hex值，实际上就是8位的字符
            // BigInteger函数则将8位的字符串转换成16位hex值，用字符串来表示；得到字符串形式的hash值
            return new BigInteger(1, md.digest()).toString(16);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 字符串签名
     *
     * @param str -字符串
     * @return 128位hex
     */
    public static String sign128(String str) {
        try {
            // 使用sha512签名
            MessageDigest md = MessageDigest.getInstance("SHA-512");
            md.update(str.getBytes());
            return bytesToHexStr(md.digest());
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 指定字符串计算8位uuid
     *
     * @param feed - 源字符串
     * @return String
     */
    public static String uuid(String feed) {
        if (StringUtil.isBlank(feed)) {
            feed = UUID.randomUUID().toString();
        }
        String uuid = md5(feed) + Math.abs(feed.hashCode());
        char[] chars = uuid.toCharArray();
        StringBuilder sb = new StringBuilder();

        int len = chars.length - 1;
        for (int i = 0; i < 8; i++) {
            sb.append(chars[ThreadLocalRandom.current().nextInt(len)]);
        }
        return sb.toString();
    }

    public static String substringAfterLast(final String str, final String separator) {
        if (isEmpty(str)) {
            return str;
        }
        if (isEmpty(separator)) {
            return EMPTY;
        }
        final int pos = str.lastIndexOf(separator);
        if (pos == -1 || pos == str.length() - separator.length()) {
            return EMPTY;
        }
        return str.substring(pos + separator.length());
    }

}

